#include "imit_ngx_mempool.h"

memory_pool * memory_pool::createPool(size_t capacity)
{
    /*先分配一大段连续内存，该段内存由pool,small_block,small_buff组成*/
    size_t total_size              = sizeof(memory_pool) + sizeof(small_block)+ capacity;
    void * temp                    =malloc(total_size);
    memset(temp , 0 , total_size);
    memory_pool * pool             = (memory_pool *)temp;
    pool->small_buff_capacity      = capacity;
    pool->big_block_start          = nullptr;
    pool->cur_usable_small_block   = (small_block *)(pool->small_block_start);
    small_block * sbp              = (small_block *)(pool + 1);
    sbp->cur_usable_buffer         = (char *)(sbp + 1);
    sbp->buffer_end                = sbp->cur_usable_buffer + capacity;
    sbp->next_block                = nullptr;
    sbp->no_enough_times           = 0;
    fprintf(stdout,"pool_adress:%p\n", pool);
    fprintf(stdout,"first_small_block_adress:%p\n",sbp);
    fprintf(stdout,"first_small_buffer_adress:%p\n", sbp->cur_usable_buffer);
    return pool;
}

void memory_pool::destroyPool(memory_pool * pool){
    //销毁大内存
    big_block * bbp                = pool->big_block_start;
    while(bbp){
        if(bbp->big_buffer){
            free(bbp->big_buffer);
            bbp->big_buffer        = nullptr;
        }
        bbp                        = bbp->next_block;
    }
    //big_block在小内存池中销毁
    //销毁小内存
    small_block * temp             = pool -> small_block_start->next_block;
    while(temp){
        small_block * next         = temp -> next_block;
        free(temp);
        temp                       = next;
    }
    free(pool);
}

char* memory_pool::createNewSmallBlock(memory_pool * pool,size_t size){
    //创建新的small_block
    size_t malloc_size             = sizeof(small_block)+pool->small_buff_capacity;
    void * temp                    = malloc(malloc_size);
    memset(temp,0,malloc_size);
    //初始化新的small block
    small_block * sbp              = (small_block *)temp;
    sbp -> cur_usable_buffer       = (char*)(sbp+1);//跨过一个small_block的步长
    sbp -> buffer_end              = (char*)temp+malloc_size;
    sbp -> next_block              = nullptr;
    sbp -> no_enough_times         = 0;
    //预留size空间给新分配的内存
    char* res                      = sbp -> cur_usable_buffer;//存个副本作为返回值
    sbp -> cur_usable_buffer       = res+size;
    fprintf(stdout,"new_small_block_address:%p\n",sbp);
    fprintf(stdout,"new_small_buffer_address:%p\n",sbp->cur_usable_buffer);
    //更新cur_usable_small_block，也就是寻找的起点
    small_block * p                = pool -> cur_usable_small_block;
    while(p->next_block){//除非没有下一个small_block
        if(p->no_enough_times>4){
            pool -> cur_usable_small_block = p->next_block;//判断该块的申请失败的次数，当次数大于4时，该块之前的block就不再寻找分配小内存
        }
        ++(p->no_enough_times);//进入该函数，说明所有的块的内存肯定不够用，全部no_enough_times都+1
        p = p->next_block;
    }
 
    //此时p正好指向当前pool中最后一个small_block,将新节点接上去。
    p->next_block                 = sbp;
 
    //判断最后一个block的no_enough_times是否大于4而导致cur_usable_small_block为nullptr
    if(pool -> cur_usable_small_block == nullptr){
        pool -> cur_usable_small_block = sbp;
    }
    return res;
}

char* memory_pool::mallocBigBlock(memory_pool * pool,size_t size){
    //分配size大小的空间
    void*temp                     = malloc(size);
    memset(temp, 0, size);
 
    //从big_block_start开始寻找,由于big block是一个栈式链，插入新元素是插入到头结点的位置。
    big_block * bbp = pool->big_block_start;
    int i = 0;
    while(bbp){
        if(bbp->big_buffer == nullptr){
            bbp->big_buffer       = (char*)temp;
            return bbp->big_buffer;
        }
        if(i>3){
            break;//为了保证效率，如果找三轮还没找到有空buffer的big_block，就直接建立新的big_block
        }
        bbp                       = bbp->next_block;
        ++i;
    }

    big_block* new_bbp            = (big_block*)memory_pool::poolMalloc(pool,sizeof(big_block));
    new_bbp -> big_buffer         = (char*)temp;
    new_bbp ->next_block          = pool->big_block_start;
    pool -> big_block_start       = new_bbp;
 
    return new_bbp->big_buffer;
}

void* memory_pool::poolMalloc(memory_pool * pool,size_t size){
    //判断是大内存还是小内存
    if(size<pool->small_buff_capacity){//如果是小内存
        //从cur small block开始寻找
        small_block * temp       = pool -> cur_usable_small_block;
        do{
            //判断当前small block的buffer够不够分配，如果够分配,直接返回
            if(temp->buffer_end-temp->cur_usable_buffer>size){
                char * res      = temp->cur_usable_buffer;
                temp -> cur_usable_buffer = temp->cur_usable_buffer+size;
                return res;
            }
            temp                = temp->next_block;
        }while (temp);
        //如果最后一个small block都不够分配，则创建新的small block;
        return createNewSmallBlock(pool,size);
    }
    //分配大内存
    return mallocBigBlock(pool,size);
}

void memory_pool::freeBigBlock(memory_pool * pool, char *buffer_ptr){//nginx只回收大内存，不回收小内存
    big_block* bbp             = pool -> big_block_start;
    while(bbp){
        if(bbp->big_buffer == buffer_ptr){
            free(bbp->big_buffer);
            bbp->big_buffer   = nullptr;
            return;
        }
        bbp                   = bbp->next_block;
    }
}